home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / arc / dmscheck.lha / dmscheck.c
C/C++ Source or Header  |  1991-08-23  |  14KB  |  592 lines

  1. /*
  2.  * DMS-check: by ????????, the unknown programmer
  3.  *
  4.  * This is a program for checking "dms" files on unix systems.
  5.  * Its usage is:
  6.     dmscheck <option> files ...
  7.  *
  8.  * Options are:
  9.     -h or -? : little help
  10.     -s : silent mode. No output at all, only status returned.
  11.     -v : verbose mode. Gives the content of the file.
  12.     -d : debug mode. Very verbose.
  13.  
  14.  * In standart mode, you only get a message "FILE GOOD" or "FILE BAD"
  15.  * for each file you specify.
  16.  * The code is pretty basic Unix, there should be no compiling problem,
  17.  * just do "cc dmscheck.c -o dmscheck" to get the executable.
  18.  * Care was taken to read and use the data as char arrays to avoid
  19.  * alignement problems inside structures (a main portability nuisance).
  20.  *
  21.  * NB: People with little endian machines should define LITTLEINDIAN below.
  22.  *     If you're not sure then try out normally. If it fails/coredumps, try with
  23.  *     debug flag (-d) and see if CRC's are backwards. If yes: define it.
  24.  * [little-endian compatibility by Geoff C. Wing (gwing@mullauna.cs.mu.oz.au)]
  25.  * that's right, blame it on me if it doesn't work anymore for big-endians :-)
  26.  *
  27.  * TODO: a bit more error checking, I reckon.
  28.  */
  29. /* #define LITTLEINDIAN /* for little-endian machines */
  30.  
  31. #include <stdio.h>
  32. #include <sys/types.h>
  33. #include <sys/file.h>
  34.  
  35. #define BOXSIZE    5
  36.  
  37. #define MAXTRACKS 85
  38.  
  39. typedef char BYTE;
  40. typedef unsigned char UBYTE;
  41. typedef short SHORT;
  42. typedef unsigned short USHORT;
  43. typedef long LONG;
  44. typedef unsigned long ULONG;
  45.  
  46. #define SILENT 0
  47. #define NORMAL 1
  48. #define VERBOSE 2
  49. #define DEBUG  3
  50.  
  51. int MessageLevel = NORMAL ;
  52.  
  53. #define NOERROR 0
  54. #define NONFATAL 1
  55. #define FATAL 2
  56.  
  57. int BadFileFlag = 0 ;
  58. int GlobalStatus = 0 ;
  59.  
  60. int FirstTrack = 0 ;
  61. int LastTrack = 0 ;
  62.  
  63. char Tracks[MAXTRACKS] ;
  64.  
  65. char IoBuf[60000] ;
  66. USHORT Crc ;
  67.  
  68. /* Format of a simple DMS file:
  69.  
  70.     Ident File_Head CRC Track_Head CRC Data Track_Head CRC Data  ....
  71.  
  72. */
  73.  
  74. char Ident[6] ;            /* "DMS!" */
  75.  
  76. /* 
  77.    These macros are used to access the file header components
  78.    with no concern about the alignement requirements of each machine.
  79. */
  80.  
  81. #ifdef LITTLEINDIAN
  82. #define little_swap_short(a) (((a & 0x00ff) << 8) \
  83.                 + ((a & 0xff00) >> 8))
  84. #define little_swap_long(a)  (((a & 0x000000ff) << 24) \
  85.                 + ((a & 0x0000ff00) <<  8) \
  86.                 + ((a & 0x00ff0000) >>  8) \
  87.                 + ((a & 0xff000000) >> 24)) 
  88. #else /* not LITTLEINDIAN */
  89. #define little_swap_short(a)  (a)
  90. #define little_swap_long(a)   (a)
  91. #endif /* not LITTLEINDIAN */
  92.  
  93. #define DHEAD_FROM(tab)  (SHORT)little_swap_short(*((SHORT *) (tab+12)))
  94. #define DHEAD_TO(tab)    (SHORT)little_swap_short(*((SHORT *) (tab+14)))
  95. #define DHEAD_CSIZE(tab) (ULONG)little_swap_long(*((ULONG *) (tab+16)))
  96. #define DHEAD_SIZE(tab)  (ULONG)little_swap_long(*((ULONG *) (tab+20)))
  97. #define DHEAD_MODE(tab)  (SHORT)little_swap_short(*((SHORT *) (tab+48)))
  98.  
  99. char DHeader[50] ;
  100.  
  101. struct File_Head        /*offset - sizeof(File_Head) = 50 */
  102. {
  103.     long u1  ;        /* 0 -  ???? */
  104.     long u2  ;        /* 4 -  ???? */
  105.     long date ;        /* 8 - Creation date of file */
  106.     short from ;        /*12 - index of first track */
  107.     short to ;         /*14 - index of last track */
  108.     ULONG  size_after ;    /*16 - total size of data after compression */
  109.     ULONG  size_before ;    /*20 - total size of data before compression */
  110.     long u3 ;        /*24 -  0 */
  111.     short cpu ;        /*28 -  Cpu type ( 1:68000, 2:68010, ... ) */
  112.     short copross ;     /*30 -  Cpu coprocessor ( 1:68881 ) */
  113.     short machine ;        /*32 -  Machine used ( 1:Amiga, 2:PC, ...) */
  114.     short u4 ;        /*34 -  ??? */
  115.     short cpu_speed ;    /*36 -  */
  116.     long time ;        /*38 -  Time to create archive in sec. */
  117.     short c_version ;    /*42 -  Version of creator (66, 67, 68) */
  118.     short n_version ;    /*44 -  Version needed to extract */
  119.     short disk_type ;    /*46 -  Disktype of archive */
  120.     short cmode ;        /*48 -  compression mode 0-4 */
  121. } ;
  122.  
  123. char THeader[18] ;
  124.  
  125. #define THEAD_IDENT(tab) (USHORT)little_swap_short(*((USHORT *) (tab+0 )))
  126. #define THEAD_TNUM(tab)  (SHORT)little_swap_short(*((SHORT *)  (tab+2 )))
  127. #define THEAD_SIZE(tab)  (ULONG)little_swap_long(*((ULONG *)  (tab+4 )))
  128. #define THEAD_DCRC(tab)  (USHORT)little_swap_short(*((USHORT *) (tab+16)))
  129.  
  130. struct Track_Head        /*offset -  sizeof(Track_Head) = 18 */
  131. {
  132.     short delim ;        /* 0 - delimiter, 0x5452, is 'TR' */
  133.     short number ;        /* 2 - track number, -1 if text */
  134.     ULONG size ;        /* 4 - size of data part */
  135.     USHORT plength ;    /* 8 - length of non-encoded data */
  136.     USHORT ulength ;    /*10 - length of encoded data */
  137.     short mode ;        /*12 - encryption mode(0: simple, 102: quick)*/
  138.     USHORT usum ;        /*14 - raw data checksum */
  139.     USHORT dcrc ;        /*16 - data CRC */
  140. } ;
  141.  
  142.  
  143. static USHORT CRCTab[256]=
  144. {
  145.     0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
  146.     0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
  147.     0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
  148.     0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
  149.     0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
  150.     0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
  151.     0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
  152.     0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
  153.     0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
  154.     0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
  155.     0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
  156.     0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
  157.     0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
  158.     0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
  159.     0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
  160.     0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
  161.     0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
  162.     0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
  163.     0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
  164.     0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
  165.     0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
  166.     0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
  167.     0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
  168.     0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
  169.     0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
  170.     0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
  171.     0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
  172.     0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
  173.     0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
  174.     0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
  175.     0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
  176.     0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
  177. };
  178.  
  179. USHORT DoBlockCRC(Mem, Size)
  180. UBYTE* Mem;
  181. int Size ;
  182. {
  183.     register USHORT CRC = 0;
  184.  
  185.     while(Size--)
  186.         CRC = CRCTab[((CRC ^ *Mem++) & 255)] ^ ((CRC >> 8) & 255);
  187.  
  188.     return (CRC) ;
  189. }
  190.  
  191. #define MAXFILES 250 
  192.  
  193. char * ListOfFiles[MAXFILES] ;
  194. int NumberOfFiles ;
  195.  
  196. static void AppendFileName(f)
  197. char * f;
  198. {
  199.     if ( NumberOfFiles >= MAXFILES )
  200.     {
  201.         printf("\tToo many files. Max is %d\n",MAXFILES) ;
  202.         exit(1) ;
  203.     }
  204.     else
  205.     {
  206.         ListOfFiles[NumberOfFiles++] = f ;
  207.     }
  208. }
  209.  
  210. static void ReadError(s,n)
  211. char* s;
  212. int n;
  213. {
  214.     if ( MessageLevel >= VERBOSE )
  215.         printf("\tError reading %s (%d char read)\n",s,n) ;
  216. }
  217.  
  218. static void WhereInFile(fd,s)
  219. int fd ;
  220. char *s;
  221. {
  222.     int init;
  223.  
  224.     init = lseek(fd, 0L, L_INCR) ;
  225.     if ( MessageLevel >= DEBUG )
  226.         printf("\tStarting read of %s at offset %d\n",s,(int) init ) ;
  227. }
  228.  
  229. /*
  230.  * Handling track data
  231.  *
  232.  */
  233.  
  234. static void ReadTrackHeader(fd)
  235. int fd ;
  236. {
  237.     int n_read ;
  238.  
  239.     WhereInFile(fd,"Track header") ;
  240.  
  241.     n_read = read(fd, THeader, sizeof(THeader) ) ;
  242.     if ( n_read != sizeof(THeader)  )    
  243.     {
  244.         ReadError("Theader DATA",n_read) ;
  245.         BadFileFlag = FATAL;
  246.         return;
  247.     }
  248.  
  249.     n_read = read(fd, (char *) &Crc, 2) ;
  250.     if ( n_read != 2 )    
  251.     {
  252.         ReadError("THeader CRC",n_read) ;
  253.         BadFileFlag = FATAL;
  254.     }
  255.     Crc = little_swap_short(Crc);
  256. }
  257.  
  258. static void VerifyTrackHeader()
  259. {
  260.     USHORT crc ;
  261.  
  262.     if ( THEAD_IDENT(THeader) != 0x5452 )    /* Magic string "TR" */
  263.     {
  264.         if ( MessageLevel >= VERBOSE )
  265.             printf("\tBAD THeader identifier: %4x\n",
  266.                     (int) THEAD_IDENT(THeader) );
  267.  
  268.         BadFileFlag = FATAL ;
  269.         return ;
  270.     }
  271.  
  272.     crc = DoBlockCRC( THeader, sizeof(THeader) ) ;
  273.  
  274.     if ( crc != Crc )
  275.     {
  276.         if ( MessageLevel >= VERBOSE )
  277.             printf("\tBAD THeader checksum. Read %4x, computed %4x\n",
  278.                                (int) Crc, (int) crc ) ;
  279.         BadFileFlag = FATAL ;    /* size is not sure */
  280.     }
  281.     else if ( MessageLevel >= DEBUG )
  282.         printf("\tTrack Header checksum OK (%4x)\n",(int) crc ) ;
  283. }
  284.  
  285. static void ReadTrackData(fd)
  286. int fd ;
  287. {
  288.     int n_read ;
  289.  
  290.     if ( MessageLevel >= DEBUG )
  291.             printf("\tSize of track data: %d\n", (int) THEAD_SIZE(THeader) );
  292.  
  293.     n_read = read(fd, IoBuf, (int) THEAD_SIZE(THeader)) ;
  294.     if ( n_read != THEAD_SIZE(THeader) )    
  295.     {
  296.         ReadError("track data",n_read) ;
  297.         BadFileFlag = FATAL ; 
  298.         return;
  299.     }
  300. }
  301.  
  302.  
  303. static void VerifyTrackData()
  304. {
  305.     USHORT crc ;
  306.  
  307.     crc = DoBlockCRC( IoBuf, (int) THEAD_SIZE(THeader) );
  308.  
  309.     if ( crc != THEAD_DCRC(THeader) )
  310.     {
  311.         if ( MessageLevel >= VERBOSE )
  312.         {
  313.                 printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
  314.         printf("-BAD CRC: read %4x, computed %4x\n",
  315.                 (int) THEAD_DCRC(THeader), (int) crc ) ;
  316.         }
  317.         BadFileFlag = NONFATAL ;
  318.     }
  319.     else if ( MessageLevel >= VERBOSE )
  320.     {
  321.             printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
  322.         printf("-GOOD CRC: %4x\n",(int) crc ) ;
  323.     }
  324. }
  325.  
  326. static void UpdateTrackCount()
  327. {
  328.     Tracks[(int) THEAD_TNUM(THeader)] = 1 ;
  329. }
  330.  
  331. static void TreatTrackHunk(fd)
  332. int fd ;
  333. {
  334.     ReadTrackHeader(fd) ;
  335.  
  336.     if ( BadFileFlag != FATAL )
  337.         VerifyTrackHeader() ;
  338.     
  339.     if ( BadFileFlag != FATAL )
  340.         ReadTrackData(fd) ;
  341.  
  342.     if ( BadFileFlag != FATAL )
  343.         VerifyTrackData() ;
  344.  
  345.     if ( BadFileFlag != FATAL )
  346.         UpdateTrackCount() ;
  347. }
  348.  
  349. static int MoreTrackToRead()
  350. {
  351.     return (( Tracks[LastTrack] ) ? 0 : 1) ;
  352. }
  353.  
  354. static void TreatTracks(fd)
  355. int fd ;
  356. {
  357.     while ( BadFileFlag != FATAL && MoreTrackToRead() )
  358.         TreatTrackHunk(fd) ;
  359. }
  360.  
  361. static void InitialiseTrackData()
  362. {
  363.     int i;
  364.  
  365.     BadFileFlag = 0 ;
  366.  
  367.     for ( i= 0; i< MAXTRACKS; i++ )
  368.         Tracks[i] = 0 ;
  369. }
  370.  
  371. /*
  372.  * Handling one file dms header
  373.  *
  374.  */
  375.  
  376. void VerifyDHeader()
  377. {
  378.     USHORT crc ;
  379.  
  380.     if ( strncmp(Ident, "DMS!", 4 ) )
  381.     {
  382.         if ( MessageLevel >= NORMAL )
  383.         printf("\tThis is *not* a dms archive\n") ;
  384.         BadFileFlag = FATAL ; 
  385.         return;
  386.     }
  387.  
  388.     crc = DoBlockCRC(DHeader, sizeof(DHeader) ) ;
  389.  
  390.     if ( crc != Crc )
  391.     {
  392.         if ( MessageLevel >= VERBOSE )
  393.         printf("\tBAD file header checksum. Read %4x, computed %4x\n",
  394.                     (int) Crc, (int) crc) ;
  395.         BadFileFlag = FATAL ;
  396.     }
  397.     else if ( MessageLevel >= DEBUG )
  398.         printf("\tDms Header checksum OK (%4x = %4x)\n",
  399.                         (int) crc, (int) Crc );
  400. }
  401.  
  402. static void UpdateFileData()
  403. {
  404.  
  405.     if ( MessageLevel >= VERBOSE )
  406.     {
  407.         printf("\tContains tracks: %d to %d\n",
  408.             (int) DHEAD_FROM(DHeader), (int) DHEAD_TO(DHeader) );
  409.  
  410.        printf("\tCompression mode: %d\n", (int) DHEAD_MODE(DHeader)) ;
  411.        printf("\tData sizes: raw: %d     compressed: %d\n",
  412.             (int) DHEAD_SIZE(DHeader), (int) DHEAD_CSIZE(DHeader));
  413.     }
  414.  
  415.     FirstTrack = (int) DHEAD_FROM(DHeader) ;
  416.     LastTrack = (int) DHEAD_TO(DHeader) ;
  417. }
  418.  
  419. void ReadDHeader(fd)
  420. int fd ;
  421. {
  422.     int n_read ;
  423.  
  424.     WhereInFile(fd,"Ident") ;
  425.  
  426.     n_read = read(fd, Ident, 4) ;
  427.     if ( n_read < 4 )    
  428.     {
  429.         ReadError("Ident",n_read) ;
  430.         BadFileFlag = FATAL ; 
  431.         return ;
  432.     }
  433.  
  434.     WhereInFile(fd,"DHeader") ;
  435.  
  436.     n_read = read(fd, DHeader, sizeof(DHeader)) ;
  437.     if ( n_read < sizeof(DHeader) )    
  438.     {
  439.         ReadError("DHeader DATA",n_read) ;
  440.         BadFileFlag = FATAL ; 
  441.         return ;
  442.     }
  443.  
  444.     n_read = read(fd, (char *) &Crc, 2) ;
  445.     if ( n_read < 2 )    
  446.     {
  447.         ReadError("DHeader CRC",n_read) ;
  448.         BadFileFlag = FATAL ;
  449.     }
  450.     Crc = little_swap_short(Crc);
  451. }
  452.  
  453. void TreatDHeader(fd)
  454. int fd ;
  455. {
  456.     ReadDHeader(fd) ;
  457.  
  458.     if ( BadFileFlag != FATAL )
  459.         VerifyDHeader() ;
  460.  
  461.     if ( BadFileFlag != FATAL )
  462.         UpdateFileData() ;
  463. }
  464.  
  465. /*
  466.  * Handling one file
  467.  *
  468.  */
  469.  
  470. static void TreatFile(file_)
  471. char * file_ ;
  472. {
  473.     int fd ;
  474.  
  475.     if ( (fd = open(file_, 0)) == -1 )
  476.     {
  477.         fprintf(stderr,"\tError opening file: %s\n", file_) ;
  478.         return ;
  479.     }
  480.  
  481.     if ( NumberOfFiles > 1 && MessageLevel >= NORMAL )
  482.         printf("Treating file: %s\n", file_ ) ;
  483.  
  484.     InitialiseTrackData() ;
  485.  
  486.     TreatDHeader(fd) ;
  487.  
  488.     if ( BadFileFlag != FATAL )
  489.         TreatTracks(fd) ;
  490.  
  491.     if ( BadFileFlag )
  492.     {
  493.         if ( MessageLevel >= NORMAL )
  494.         printf("\t>>> FILE BAD\n") ;
  495.         GlobalStatus = 1 ;
  496.     }
  497.     else if ( MessageLevel >= NORMAL )
  498.         printf("\t>>> FILE GOOD\n" ) ;
  499.  
  500.     close(fd) ;
  501. }
  502.  
  503. /*
  504.  * Various intialisations and command line handle
  505.  *
  506.  */
  507.  
  508. static PrintHelp()
  509. {
  510.     puts("Valid options are:") ;
  511.     puts("\t-s : silent") ;
  512.     puts("\t-v : verbose") ;
  513.     puts("\t-d : debug (very verbose)") ;
  514.     puts("\t-h,-? : help") ;
  515.  
  516.     exit(0) ;
  517. }
  518.  
  519. static int DecodeOption(argv, arg)
  520. char * argv[] ;
  521. int arg ;
  522. {
  523.         char *argp = argv[arg]+1 ;
  524.  
  525.         switch ( *argp )
  526.         {
  527.             case 's':
  528.                  MessageLevel = SILENT ;
  529.                  return (arg+1) ;
  530.  
  531.             case 'v':
  532.                  MessageLevel = VERBOSE ;
  533.                  return (arg+1) ;
  534.  
  535.             case 'd':
  536.          MessageLevel = DEBUG ;
  537.                  return (arg+1) ;
  538.  
  539.             case 'h':
  540.         case '?':
  541.         default:
  542.          PrintHelp() ;
  543.                  return (arg+1) ;        /* Not executed */
  544.  
  545.     }
  546. }
  547.  
  548.  
  549. void DecodeArgLine(argc, argv)
  550. int argc ;
  551. char * argv[] ;
  552. {
  553.       int arg ;
  554.  
  555.     if ( argc <= 1)
  556.     {
  557.         PrintHelp() ;
  558.     }
  559.  
  560.         for ( arg = 1; arg < argc ; )
  561.         {
  562.             if ( *argv[arg] != '-' )
  563.             {
  564.                 AppendFileName(argv[arg]) ;
  565.                 arg += 1 ;
  566.             }
  567.             else
  568.                 arg = DecodeOption(argv,arg) ;
  569.         }
  570. }
  571.  
  572. /*
  573.  * Main part
  574.  *
  575.  */
  576.  
  577. int main(argc,argv)
  578. int argc ;
  579. char ** argv ;
  580. {
  581.     int i;
  582.     
  583.     DecodeArgLine(argc, argv) ;
  584.     
  585.     for ( i=0 ; i< NumberOfFiles; i++ )
  586.     {
  587.         TreatFile(ListOfFiles[i]) ;
  588.     }
  589.  
  590.     return ( GlobalStatus ) ;
  591. }
  592.